import threading
import uuid

from fastapi.middleware.cors import CORSMiddleware
from fastapi import FastAPI, Query
from business.business_constant import BusinessConstant
from business.test_business import TestBusiness
from dev_control.dev_control_api import DevControlApi
from dji_redis.redis_client import RedisClient
from utils.drone_util import DroneUtil
app = FastAPI()
from os.path import abspath, join, dirname
import sys
from datetime import datetime, timedelta

# 插入proto目录到sys.path
sys.path.insert(0, join(abspath(dirname(__file__))))
from mqtt.mqtt_subscription import MqttSubscription
from req_modal import (ApiResponse, getPointsReq, flyToReq, cloudControlAuthReq, flyPointsReq,
                       flyPointsLookReq, takeoffPointReq, photoReq, AimReq, LookAtReq, DrcModeEnterReq)
from drone.drone_api import DroneApi
from sn.sn_manager import SnManager
sn_manager =  SnManager()
redis_client = RedisClient()
# 允许所有来源的请求
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源的请求
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法（GET、POST、PUT、DELETE 等）
    allow_headers=["*"],  # 允许所有请求头
)

drone_api = DroneApi()
dev_control_api = DevControlApi()
test_business = TestBusiness()
gateway_sn = SnManager.gateway_sn_list[0]

# 以某个点为圆心，半径r，隔一定°获取一个点
@app.post("/api/get_points")
async def get_points(req: getPointsReq):
    try:
        interval_degrees = 360 / req.points_num
        points = []
        for n in range(1, req.points_num+1):
            new_lat, new_lon = DroneUtil.calculate_rotated_point(req.lat,
                                                                 req.lng,
                                                                 req.radius_meters,
                                                                 n,
                                                                 int(interval_degrees))
            points.append({ 'lat': new_lat, 'lng': new_lon})
        return ApiResponse(code=0, result=points, message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))


@app.post("/api/fly_to_points")
async def fly_to_points(req: flyToReq):
    try:
        fly_to_id = str(uuid.uuid4())
        request = {
            "fly_to_id": fly_to_id,
            "max_speed": req.speed,
            "points": [
                {
                    "height": req.height,
                    "latitude": req.latitude,
                    "longitude": req.longitude
                }
            ]
        }
        drone_api.fly_to_point(gateway_sn, request)
        return ApiResponse(code=0, result=fly_to_id, message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

@app.post("/api/cloud_control_auth_request")
async def cloud_control_auth_request(req: cloudControlAuthReq):
    try:
        drone_api.cloud_control_auth_request(gateway_sn=gateway_sn,
                                             request=req.to_dict())
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 释放云端控制
@app.get("/api/cloud_control_release")
async def cloud_control_release():
    try:
        req = {"control_keys": ["flight"]}
        drone_api.cloud_control_release(gateway_sn=gateway_sn,
                                        request=req)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 进入指令飞行控制模式
@app.post("/api/drc_mode_enter")
async def drc_mode_enter(req: DrcModeEnterReq):
    try:
        # 获取当前时间
        current_time = datetime.now()
        # 加上一天
        one_day_later = current_time + timedelta(days=1)
        # 转换为时间戳
        timestamp_one_day_later = int(one_day_later.timestamp())
        print(timestamp_one_day_later)
        req.expire_time = timestamp_one_day_later
        drone_api.drc_mode_enter(gateway_sn=gateway_sn,
                                        request=req.to_dict())
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))


# 退出指令飞行控制模式
@app.get("/api/drc_mode_exit")
async def drc_mode_exit():
    try:
        drone_api.drc_mode_exit(gateway_sn=gateway_sn,
                                        request={})
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 一键起飞
@app.post("/api/takeoff_to_point")
async def takeoff_to_point(req: takeoffPointReq):
    try:
        drone_api.takeoff_to_point(gateway_sn=gateway_sn,
                                        request=req.to_dict())
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 结束飞目标点任务
@app.get("/api/fly_to_point_stop")
async def fly_to_point_stop():
    try:
        drone_api.fly_to_point_stop(gateway_sn=gateway_sn)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 更新飞行目标点
@app.post("/api/fly_to_point_update")
async def fly_to_point_update(req: flyToReq):
    try:
        request = {
            "max_speed": req.speed,
            "points": [
                {
                    "height": req.height,
                    "latitude": req.latitude,
                    "longitude": req.longitude
                }
            ]
        }
        drone_api.fly_to_point_update(gateway_sn, request)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))
# 一键返航
@app.get("/api/return_home")
async def return_home():
    try:
        drone_api.return_home(gateway_sn)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 取消一键返航
@app.get("/api/return_home_cancel")
async def return_home_cancel():
    try:
        drone_api.return_home_cancel(gateway_sn)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 双击成为 AIM
@app.post("/api/aim_at")
async def aim_at(req: AimReq):
    try:
        dev_control_api.aim_at(gateway_sn, req.to_dict())
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 功能指飞行器将从当前朝向转向实际经纬高度指定的点
@app.post("/api/look_at")
async def look_at(req: LookAtReq):
    try:
        dev_control_api.look_at(gateway_sn, req.to_dict())
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

#负载控制—开始拍照
@app.post("/api/photo_take")
async def photo_take(req: photoReq):
    try:
        dev_control_api.photo_take(gateway_sn, req.to_dict())
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 负载控制—停止拍照
@app.post("/api/photo_stop")
async def photo_stop(req: photoReq):
    try:
        dev_control_api.photo_stop(gateway_sn, req.to_dict())
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

@app.post("/api/fly_points")
async def fly_points(req: flyPointsReq):
    try:
        test_business.fly_points(gateway_sn=gateway_sn, req=req)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

@app.post("/api/fly_points_look")
async def fly_points_look(req: flyPointsLookReq):
    try:
        test_business.fly_points_lookat(gateway_sn=gateway_sn,
                                        points=req.points,
                                        lookat_request=req.lookPointReq)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

# 获取目标的经纬度
@app.post("/api/target_location_business")
async def target_location_business():
    try:
        test_business.target_location_business(gateway_sn=gateway_sn)
        return ApiResponse(code=0, result="success", message="")
    except Exception as e:
        return ApiResponse(code=1, result=str(e), message=str(e))

business_constant = BusinessConstant()
@app.get('/api/logs')
async def get_logs(log_type: int = Query(..., description="日志类型")):
    log_key = business_constant.DEV_INFO_LOG_KEY if log_type == 1 else business_constant.SERVICES_REPLY_LOG_KEY
    if log_type == 1:
        return ApiResponse(code=0, result=[], message="")
    else:
        logs = redis_client.get_list(log_key, 0, business_constant.MESSAGE_LIMIT - 1)
        return ApiResponse(code=0, result=logs, message="")


def mqtt_sub():
    sub = MqttSubscription()
    sub.start()

# 启动应用的入口
if __name__ == "__main__":
    import uvicorn
    thread = threading.Thread(target=mqtt_sub)
    thread.start()
    uvicorn.run(app, host="0.0.0.0", port=8000)

